﻿#include "unrealircd.h"

/*
此模块存放数据库的配置函数

*/

int database_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
int database_config_posttest(int *errs);
int database_config_run(ConfigFile *cf, ConfigEntry *ce, int type);
int database_init();
void config_conninfo(char *conninfos);
int db_Command_to_Prepared(DB_Command_Prepared prepared, Result_Func func);
int db_queryByPerpared(DB_Command_Value command_value, DB_Rsult_Data *result_data);
int db_config_prepared();
int result_func_add(char* sql_name, int(*func)(PGresult *result, DB_Rsult_Data *result_data));
Result_Func result_func_select(char *sql_name);
int insert_byPerpared(DB_Command_Value command_value, DB_Rsult_Data *result_data);

//模块内部定义的变量
char *databaseUrl, *databaseUsername, *databasePassword, *databaseName;
int databasePort = 0;
int urlExit = 0, userNameExit = 0, passwordExit = 0, nameExit = 0, portExit = 0;
PGconn *postgreSQl_connect;
DB_Result_func_Array db_result_func_array;



//数据库测试函数
int db_test();
int db_test_QueryImUserById();




int database_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
	int errors = 0;
	ConfigEntry *cep;
	if (type != CONFIG_SET || strcmp(ce->ce_varname, "database-config"))
		return 0;
	for (cep = ce->ce_entries; cep; cep = cep->ce_next) {
		if (!cep->ce_varname) {
			config_error("%s:%i: blank set::database-config item",
				cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
			errors++;
			continue;
		}
		else if (!strcmp(cep->ce_varname, "database-url")) {
			urlExit = 1;
		}
		else if (!strcmp(cep->ce_varname, "database-port")) {
			portExit = 1;
		}
		else if (!strcmp(cep->ce_varname, "database-username")) {
			userNameExit = 1;
		}
		else if (!strcmp(cep->ce_varname, "database-password")) {
			passwordExit = 1;
		}
		else if (!strcmp(cep->ce_varname, "database-name")) {
			nameExit = 1;
		}
		else {
			config_error("%s:%i: unknown directive set::mymod::%s",
				cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
			errors++;
		}
	}
	*errs = errors;
	if (errors) {
		config_error("database module faile start in database_config_test");

	}
	return errors ? -1 : 1; /* we return 1 to say: yup this belongs to us, it's handled/good, and return -1 to indicate we encountered some error */
}
//测试模块所需要的信息是否完整
int database_config_posttest(int *errs) {
	int errors = 0;
	if (!urlExit) { config_error("set::database-config::database-url missing"); errors++; }
	if (!portExit) { config_error("set::database-config::database-port missing"); errors++; }
	if (!passwordExit) { config_error("set::database-config::database-password missing"); errors++; }
	if (!userNameExit) { config_error("set::database-config::database-username missing"); errors++; }
	if (!nameExit) { config_error("set::database-config::database-name missing"); errors++; }
	*errs = errors;
	if (errors > 0) {
		config_error("database_config_posttest");
	}
	return errors > 0 ? -1 : 0;
}
/*
获取数据库的配置信息，如下所示
set {
   database-config {
		database-url "数据库地址";
		database-port "数据库端口";
		database-username "数据库用户名";
		database-password "数据库密码";
		database-name "数据库名";
	};
};
*/
int database_config_run(ConfigFile *cf, ConfigEntry *ce, int type) {
	ConfigEntry *cep;
	if (type != CONFIG_SET || strcmp(ce->ce_varname, "database-config"))
		return 0;
	for (cep = ce->ce_entries; cep; cep = cep->ce_next) {
		if (!strcmp(cep->ce_varname, "database-url")) {
			databaseUrl = strdup(cep->ce_vardata);
		}
		else if (!strcmp(cep->ce_varname, "database-port")) {
			databasePort = atoi(cep->ce_vardata);
		}
		else if (!strcmp(cep->ce_varname, "database-username")) {
			databaseUsername = strdup(cep->ce_vardata);
		}
		else if (!strcmp(cep->ce_varname, "database-password")) {
			databasePassword = strdup(cep->ce_vardata);
		}
		else if (!strcmp(cep->ce_varname, "database-name")) {
			databaseName = strdup(cep->ce_vardata);
		}
	}
	return 1;
}


void config_conninfo(char *conninfos) {
	char hostaddr[100] = "";
	char port[100] = "";
	char dbname[100] = "";
	char user[100] = "";
	char password[100] = "";
	sprintf(hostaddr, "hostaddr=%s ", databaseUrl);
	sprintf(port, "port=%d ", databasePort);
	sprintf(dbname, "dbname=%s ", databaseName);
	sprintf(user, "user=%s ", databaseUsername);
	sprintf(password, "password=%s ", databasePassword);
	strcat(conninfos, hostaddr);
	strcat(conninfos, port);
	strcat(conninfos, dbname);
	strcat(conninfos, user);
	strcat(conninfos, password);
	return;
}







//数据库模块初始化，开启和数据库的连接
int database_init() {

	char conninfos[400] = "";
	config_conninfo(conninfos);
	ircd_log(LOG_DATABASE, "database module begin start in database_init conninfo:%s", conninfos);
	postgreSQl_connect = PQconnectdb(conninfos);
	if (PQstatus(postgreSQl_connect) != CONNECTION_OK) {
		ircd_log(LOG_DATABASE, "postgresql connect faile");
		PQfinish(postgreSQl_connect);
		return -1;
	}
	else {
		ircd_log(LOG_DATABASE, "postgresql connect success");
		db_config_prepared();
	}
	db_test();
	return 0;
}
//将所有SQL语句预先加载
int db_config_prepared() {
	db_result_func_array.length = 0;
	db_Command_to_Prepared(db_query_imUser_by_id, &db_PQresult_To_D_User);
	db_Command_to_Prepared(db_insert_imUser, &db_PQresult_To_D_User);
	db_Command_to_Prepared(db_query_imUser_by_user_name, &db_PQresult_To_D_User);
	db_Command_to_Prepared(db_delete_imUser, &db_PQresult_To_D_User);
	db_Command_to_Prepared(db_update_imUser, &db_PQresult_To_D_User);
	db_Command_to_Prepared(db_query_imUser_by_tel,db_PQresult_To_D_User);
	db_Command_to_Prepared(db_query_imUserFriend_by_id,db_PQresult_To_D_User);
	

	db_Command_to_Prepared(db_query_imConfigure_by_configur_name,db_PQresult_To_D_configure);

	db_Command_to_Prepared(db_query_im_third_login_by_openid_and_thirdid,db_PQresult_To_D_third_login);
	db_Command_to_Prepared(db_query_im_third_login_by_userid_and_thirdid,db_PQresult_To_D_third_login);
	db_Command_to_Prepared(db_query_im_third_login_by_userid,db_PQresult_To_D_third_login);
	db_Command_to_Prepared(db_insert_im_third_login,db_PQresult_To_D_third_login);
	db_Command_to_Prepared(db_delete_im_third_login_by_userIdAndThirdId,db_PQresult_To_D_third_login);


	db_Command_to_Prepared(db_insert_im_sms,db_PQresult_To_D_im_sms);
	db_Command_to_Prepared(db_query_im_sms_by_type_and_contactvalue,db_PQresult_To_D_im_sms);
	db_Command_to_Prepared(db_updata_im_sms_by_identity_no,db_PQresult_To_D_im_sms);

	db_Command_to_Prepared(db_insert_im_user_email, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_update_im_user_email, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_query_im_user_email_by_email, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_query_im_user_email_by_id, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_query_im_user_email_by_idAndEmail, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_query_im_user_email_by_emailAndPermition, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_query_im_user_email_by_idAndPermition, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_delete_im_user_email_by_idAndEmail, &db_PQresult_To_D_im_user_email);
	db_Command_to_Prepared(db_insert_im_login_record, &db_PQresult_To_D_im_login_record);
	
	db_Command_to_Prepared(db_insert_im_relation_applicant, &db_PQresult_To_D_im_relation_applicant);
	db_Command_to_Prepared(db_update_im_relation_applicant, &db_PQresult_To_D_im_relation_applicant);
	db_Command_to_Prepared(db_query_im_relation_applicant_by_respondentId, &db_PQresult_To_D_im_relation_applicant);
	db_Command_to_Prepared(db_query_im_relation_applicant_by_applicantId, &db_PQresult_To_D_im_relation_applicant);
	db_Command_to_Prepared(db_query_im_relation_applicant_by_relationApplicantId, &db_PQresult_To_D_im_relation_applicant);

	db_Command_to_Prepared(db_insert_im_user_relation, &db_PQresult_To_D_im_user_relation);
	db_Command_to_Prepared(db_update_im_user_relation, &db_PQresult_To_D_im_user_relation);
	db_Command_to_Prepared(db_query_im_user_relation_by_UserIdAndFriendId, &db_PQresult_To_D_im_user_relation);
	db_Command_to_Prepared(db_query_im_user_relation_by_UserId, &db_PQresult_To_D_im_user_relation);

	return 0;
}
//增加每个语句的返回值处理函数
int result_func_add(char* sql_name, Result_Func func) {
	if (db_result_func_array.length >= SQL_NUM) {
		return -1;
	}
	safe_strdup(db_result_func_array.sql_name[db_result_func_array.length],sql_name);
	db_result_func_array.func[db_result_func_array.length] = func;
	db_result_func_array.length++;
	return 1;
}

//查询sql语句的返回值处理函数
Result_Func result_func_select(char *sql_name) {
	for (int i = 0; i < db_result_func_array.length; i++) {
		if (!strcmp(db_result_func_array.sql_name[i], sql_name)) {
			return db_result_func_array.func[i];
		}
	}
	return NULL;
}

/*
进行预先加载sql语句
*/
int db_Command_to_Prepared(DB_Command_Prepared prepared, Result_Func func) {
	if (prepared.isperared) {
		return 0;
	}
	Oid *oids;
	oids = malloc(sizeof(Oid) * prepared.nParams);
	for (int i = 0; i < prepared.nParams; i++) {
		*(oids + i) = atooid(prepared.paramType[i]);
	}
	PGresult *result = PQprepare(postgreSQl_connect, prepared.stmtName, prepared.command, prepared.nParams, oids);
	ExecStatusType type = PQresultStatus(result);
	free(oids);
	if (type == PGRES_COMMAND_OK) {
		prepared.isperared = 1;
		result_func_add(prepared.stmtName, func);
		ircd_log(LOG_DATABASE, "prepared command:%s success", prepared.stmtName);
		PQclear(result);
		return 0;
	}
	else {
		ircd_log(LOG_DATABASE, "prepared command:%s faile:%d,reason:%s", prepared.stmtName, type, PQresultErrorMessage(result));
		PQclear(result);
		return -1;
	}
}

//判断数据库是否连接，如果没有连接则重新连接
int db_databaseConnectStatus(){
	if (PQstatus(postgreSQl_connect) != CONNECTION_OK) {
		char conninfos[400] = "";
		config_conninfo(conninfos);
		postgreSQl_connect = PQconnectdb(conninfos);
		if (PQstatus(postgreSQl_connect) != CONNECTION_OK) {
			ircd_log(LOG_DATABASE, "postgresql re-connect faile");
			PQfinish(postgreSQl_connect);
			return 0;
		}
		else {
			ircd_log(LOG_DATABASE, "postgresql re-connect success");
			db_config_prepared();
			return 1;
		}
	}
	return 1;
}

/*数据库查询操作，所有数据库操作都应该从此函数进行，失败返回-1，成功返回0
*@params:command_value为查询语句中替换的信息
*@params:result_data为查询结果的返回信息，不能为空，里面存放查询到的数据库实体，和实体的数目
*@return:查询错误返回-1
*/
int db_queryByPerpared(DB_Command_Value command_value, DB_Rsult_Data *result_data) {
	if(!db_databaseConnectStatus()){
		return -1;
	}
	char **paramValues = (char **)malloc(sizeof(char *)*command_value.nParams);
	for (int i = 0; i < command_value.nParams; i++) {
		paramValues[i] = command_value.paramValues[i];
		if(paramValues[i]){
			ircd_log(LOG_DATABASE, "query data %s", paramValues[i]);
		}
		else{
			ircd_log(LOG_DATABASE, "query data NULL");
		}
	}
	ircd_log(LOG_DATABASE, "begin query data");
	PGresult* result = PQexecPrepared(postgreSQl_connect, command_value.stmtName, command_value.nParams, paramValues, command_value.paramLengths, command_value.paramFormats, command_value.resultFormat);
	ExecStatusType resultType = PQresultStatus(result);
	free(paramValues);
	if (resultType == PGRES_COMMAND_OK || resultType == PGRES_TUPLES_OK) {
		ircd_log(LOG_DATABASE, "query data success");
		Result_Func func = result_func_select(command_value.stmtName);
		func(result, result_data);
		ircd_log(LOG_DATABASE, "query count:%d",result_data->datalen);
		PQclear(result);
		return 0;
	}
	else {
		ircd_log(LOG_DATABASE, "query data faile,faile code:%d,reason:%s and %s", resultType, PQresultErrorMessage(result), PQerrorMessage(postgreSQl_connect));
		PQclear(result);
		return -1;
	}
}

int insert_byPerpared(DB_Command_Value command_value, DB_Rsult_Data *result_data) {
	if(!db_databaseConnectStatus()){
		return -1;
	}
	char **paramValues = (char **)malloc(sizeof(char *)*command_value.nParams);
	for (int i = 0; i < command_value.nParams; i++) {
		paramValues[i] = command_value.paramValues[i];
	}
	PGresult* result = PQexecPrepared(postgreSQl_connect, command_value.stmtName, command_value.nParams, paramValues, command_value.paramLengths, command_value.paramFormats, command_value.resultFormat);
	ExecStatusType resultType = PQresultStatus(result);
	free(paramValues);
	if (resultType == PGRES_COMMAND_OK || resultType == PGRES_TUPLES_OK) {
		ircd_log(LOG_DATABASE, "insert data success");
		Result_Func func = result_func_select(command_value.stmtName);
		func(result, result_data);
		PQclear(result);
		return 0;
	}
	else {
		ircd_log(LOG_DATABASE, "intsert data faile,faile code:%d,reason:%s", resultType, PQresultErrorMessage(result));
		PQclear(result);
		return -1;
	}
}






//数据库测试
int db_test() {
	db_test_QueryImUserById();
	return 0;
}
int db_test_QueryImUserById() {
	int d_users_len;
	D_User *d_users = queryImUserById(1, &d_users_len);

	ircd_log(LOG_DBG, "query  data count:%d", d_users_len);
	for (int i = 0; i < d_users_len; i++) {
		ircd_log(LOG_DBG, "D_User::id=%d,git_id=%d,user_name=%s,user_password=%s,sex=%d,tel=%s",
			*d_users[i].id,
			*d_users[i].git_id,
			d_users[i].user_name,
			d_users[i].user_password,
			*d_users[i].sex,
			d_users[i].tel
		);
	}
	db_D_UserFree(d_users,d_users_len);
	return 0;
}